#include "stdafx.h"
#include "WatchDir.h"

HANDLE hChangeEvent; 

void WatchForCDorDVD(CStringArray &arString)
{
    int nArrayCount = arString.GetCount();
    CFileFind CSearchFile;
    UINT unDriveType = 0;
    CStringArray arNew;

    for(int i = 0; i < nArrayCount; ++i)
    {
        unDriveType = GetDriveType(arString[i]);

        if(unDriveType == DRIVE_CDROM)
        {
            arNew.Add(arString[i]);
        }
    }

    arString.RemoveAll();
    arString.Append(arNew);

}

bool GetVolumesList(CStringArray &arDrives)
{
    arDrives.RemoveAll();

    DWORD dwSize = GetLogicalDriveStrings(0, NULL);

    if(dwSize)
    {
        LPWSTR szDrives = new TCHAR[dwSize]; 

        dwSize = GetLogicalDriveStringsW(dwSize, szDrives);

        if (dwSize) 
        {
            CString sDrive;
            UINT i = 0;

            while(i < static_cast<UINT>(dwSize))
            {
                sDrive="";
                while(szDrives[i] != '\0')
                {
                    sDrive += szDrives[i];
                    ++i;
                }

                arDrives.Add(sDrive);

                ++i;
            }
        }

        delete [] szDrives;

        return true;
    }

    return false;
}

bool GetValidVolumes(CStringArray &arString)
{
    int nValidCount = arString.GetCount();
    CStringArray arValidList;
    CFileFind CSearchFile;

    for(int i = 0; i < nValidCount; ++i)
    {
        BOOL bResult = CSearchFile.FindFile(arString[i] + L"*");
        
        if(bResult)
        {
            arValidList.Add(arString[i]);
        }
    }
    
    arString.RemoveAll();
    arString.Append(arValidList);

    return true;
}

UINT WaitForVolumeChange(LPVOID pParam)
{
    ThreadParam* p = static_cast<ThreadParam*> (pParam);

    CStringArray arBaseVolumeList;

    if(GetVolumesList(arBaseVolumeList))
    {
        int nBaseCount = arBaseVolumeList.GetCount();
        
        WatchForCDorDVD(arBaseVolumeList);
        GetValidVolumes(arBaseVolumeList);

        int nBaseValidCount = arBaseVolumeList.GetCount();

        hChangeEvent = CreateEvent( NULL,              
                                    TRUE,               
                                    FALSE,              
                                    TEXT("ChangeEvent")); 

        while(TRUE)
        {
            Sleep(100);

            CStringArray arNewVolumeList;

            GetVolumesList(arNewVolumeList);

            int nNewCount = arNewVolumeList.GetCount();

            if(nNewCount != nBaseCount)
            {
                ::SendMessage(p->mDlg, MYMESS_CALL_VOLCOUNT_CHANGE, 0, 0);
                
                SetEvent(hChangeEvent);

                nBaseCount = nNewCount;
            }
            
            WatchForCDorDVD(arNewVolumeList);
            GetValidVolumes(arNewVolumeList);

            int nNewValidCount = arNewVolumeList.GetCount();

            if(nNewValidCount != nBaseValidCount)
            {
                Sleep(500);

                ::SendMessage(p->mDlg, MYMESS_CALL_VOL_CHANGE, 0, 0);
                SetEvent(hChangeEvent);

                nBaseValidCount = nNewValidCount;
            }
        }
    }
    
    delete p;

    CloseHandle(hChangeEvent);

    return 0;
}

UINT WaitForDirectoryChange(LPVOID pParam)
{
    ThreadParam* p = static_cast<ThreadParam*> (pParam);

    CStringArray arVolumesList;

    if(!GetVolumesList(arVolumesList))
    {
        delete p;
        return 0;
    }

    if(!GetValidVolumes(arVolumesList))
    {
        delete p;
        return 0;
    }

    int nValidVolumesCount = arVolumesList.GetCount();

    while(TRUE)
    {
        HANDLE* dwChangeHandles = new HANDLE[nValidVolumesCount+1]; 

        for(int i=0; i < nValidVolumesCount; ++i)
        {
            dwChangeHandles[i] = FindFirstChangeNotification(   arVolumesList[i],// directory to watch 
                TRUE,// do not watch subtree 
                FILE_NOTIFY_CHANGE_FILE_NAME |
                FILE_NOTIFY_CHANGE_DIR_NAME); // watch file name changes 

            if (dwChangeHandles[i] == INVALID_HANDLE_VALUE) 
            {
                FindCloseChangeNotification(dwChangeHandles[i]);

                for(int j = 0; j < i; ++j)
                {
                    FindCloseChangeNotification(dwChangeHandles[j]);
                }

                delete [] dwChangeHandles;
                delete p;
                return 0;
            }
        }

        dwChangeHandles[nValidVolumesCount] = hChangeEvent;

        while (TRUE) 
        {

            DWORD dwWaitStatus = WaitForMultipleObjects(nValidVolumesCount+1, dwChangeHandles, FALSE, INFINITE); 

            for(int i = 0; i < nValidVolumesCount; ++i)
            {
                if(dwWaitStatus == WAIT_OBJECT_0 + i)
                {
                    ::SendMessage(p->mDlg, MYMESS_CALL_DIR_CHANGE, i, 0);

                    if(FindNextChangeNotification(dwChangeHandles[i]) == FALSE)
                    {
                        for(int j = 0; j< nValidVolumesCount; ++j)
                        {
                            FindCloseChangeNotification(dwChangeHandles[j]);
                        }

                        delete [] dwChangeHandles;
                        delete p;
                        return 0;
                    }
                }
            }

            if(dwWaitStatus == WAIT_OBJECT_0 + nValidVolumesCount)
            {
                if(!GetVolumesList(arVolumesList))
                {
                    delete p;
                    return 0;
                }

                if(!GetValidVolumes(arVolumesList))
                {
                    delete p;
                    return 0;
                }

                ResetEvent(hChangeEvent);

                for(int j = 0; j< nValidVolumesCount; ++j)
                {
                    FindCloseChangeNotification(dwChangeHandles[j]);
                }

                nValidVolumesCount = arVolumesList.GetCount();

                delete [] dwChangeHandles;

                break;
            }
        }
    }

    delete p;
    return 0;
}